/*
 * 功能：用户服务类，提供用户相关的业务逻辑操作
 * 作者：张杨(Sunny)
 * 日期： 2024/10/21 下午4:24
 */
package com.example.springboot.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springboot.common.Result;
import com.example.springboot.entity.User;
import com.example.springboot.exception.ServiceException;
import com.example.springboot.mapper.UserMapper;
import com.example.springboot.utils.TokenUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 用户服务类，提供用户相关的业务逻辑处理
 */
@Service
public class UserService extends ServiceImpl<UserMapper, User> {

    @Resource
    UserMapper userMapper;


    /**
     * 重写保存用户实体的方法，确保用户信息的完整性。
     * 如果用户名、密码或角色为空，则设置默认值。
     */
    @Override
    public boolean save(User entity) {
        if(StrUtil.isBlank(entity.getName())){
            entity.setName(entity.getUsername());
        }
        if(StrUtil.isBlank(entity.getPassword())){
            entity.setPassword("0000");
        }
        if(StrUtil.isBlank(entity.getRole())){
            entity.setRole("学员");
        }
        return super.save(entity);
    }


    /**
     * 根据用户ID删除用户，如果尝试删除的是当前登录用户，则抛出异常。
     * @param id 要删除的用户ID
     * @param currentUserId 当前登录用户的ID
     */
    public void deleteUserById(Integer id, Integer currentUserId) {
        if (id.equals(currentUserId)) {
            throw new ServiceException("不能删除当前登录的用户");
        }
        userMapper.deleteById(id);
    }


    /**
     * 分页查询用户信息，可以根据用户名、姓名和角色进行筛选。
     * @param pageNum 当前页码
     * @param pageSize 每页显示的记录数
     * @param username 用户名（可选）
     * @param name 姓名（可选）
     * @param role 角色（可选）
     * @return 分页后的用户信息
     */
    public Page<User> selectByPage(Integer pageNum, Integer pageSize, String username, String name, String role, String state) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>().orderByDesc("id");
        queryWrapper.like(StrUtil.isNotBlank(username), "username", username);
        queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
        queryWrapper.eq(StrUtil.isNotBlank(role), "role", role);
        queryWrapper.eq(StrUtil.isNotBlank(state), "state", state);
        return userMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);
    }


    /**
     * 导出用户数据到Excel文件
     * @param username 用户名（用于筛选）
     * @param name 姓名（用于筛选）
     * @param ids 用户ID列表（用于筛选）
     * @param role 角色（用于筛选）
     * @param response HttpServletResponse对象，用于返回Excel文件给客户端
     * @throws IOException 如果发生I/O错误
     */
    public void exportData(String username, String name, String ids, String role, HttpServletResponse response) throws IOException {
        ExcelWriter writer = ExcelUtil.getWriter(true); // 创建Excel写入器
        List<User> list; // 用于存储查询结果的列表
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(); // 创建查询条件包装器

        // 如果ids参数不为空，则按ID筛选数据
        if (StrUtil.isNotBlank(ids)) {
            List<Integer> idsArr1 = Arrays.stream(ids.split(",")).map(Integer::valueOf).collect(Collectors.toList());
            queryWrapper.in("id", idsArr1);
        } else {
            // 否则按用户名或姓名筛选数据
            queryWrapper.like(StrUtil.isNotBlank(username), "username", username);
            queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
            queryWrapper.eq("role", role);
        }
        list = userMapper.selectList(queryWrapper); // 执行查询
        writer.write(list, true); // 将查询结果写入Excel

        // 设置响应头，指定文件类型和文件名
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename="
                + URLEncoder.encode("用户信息表", "UTF-8") + ".xlsx");

        ServletOutputStream outputStream = response.getOutputStream(); // 获取响应输出流
        writer.flush(outputStream, true); // 将Excel数据刷新到输出流
        writer.close(); // 关闭写入器
        outputStream.flush(); // 刷新输出流
        outputStream.close(); // 关闭输出流
    }

    // 导入用户数据的方法
    @Transactional
    public Result importData(MultipartFile file) throws IOException {
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        List<User> userList = reader.readAll(User.class);
        // 写入数据到数据库
        try {
            saveBatch(userList);
            return Result.success();
        } catch (Exception e) {
            return Result.error("数据批量导入错误");
        }
    }


    /**
     * 获取指定用户的未读消息数量。
     * @param username 用户名
     * @return 未读消息的数量，如果用户不存在则返回null
     */
    public String getUnRead(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        User user = userMapper.selectOne(queryWrapper);
        // 返回readMessage字段的值
        return user != null ? user.getUnRead() : null;
    }



    // 根据用户名查询用户信息。
    public User selectByUsername(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        // 根据用户名查询数据库的用户信息
        return getOne(queryWrapper);
    }

    /**
     * 用户登录验证，生成token
     *
     * @param user 包含用户名和密码的用户对象
     * @return 登录成功的用户信息，包含生成的token
     * @throws ServiceException 如果用户名不存在或密码错误
     */
    public User login(User user) {
        User dbUser = selectByUsername(user.getUsername());

        if (dbUser == null) {
            throw new ServiceException("该用户名不存在");
        }
        if (!user.getPassword().equals(dbUser.getPassword())) {
            throw new ServiceException("用户名或密码错误");
        }
        // 生成token
        String token = TokenUtils.createToken(dbUser.getId().toString(), dbUser.getPassword());
        dbUser.setToken(token);
        return dbUser;
    }


    /**
     * 用户注册，验证后直接插入数据库
     *
     * @param user 包含用户名和密码的用户对象
     * @return 注册成功的用户信息
     * @throws ServiceException 如果用户名已存在
     */
    public User register(User user) {
        User dbUser = selectByUsername(user.getUsername());

        if (dbUser != null) {
            throw new ServiceException("用户名已存在");
        }

        user.setName(user.getUsername());
        userMapper.insert(user);
        return user;
    }


    /**
     * 重置用户密码，用户名和手机号验证
     *
     * @param user 包含用户名和新密码的用户对象
     * @throws ServiceException 如果用户不存在或手机号验证错误
     */
    public void resetPassword(User user) {
        User dbUser = selectByUsername(user.getUsername());

        if (dbUser == null) {
            throw new ServiceException("用户不存在");
        }
        if (!user.getPhone().equals(dbUser.getPhone())) {
            throw new ServiceException("验证错误");
        }
        dbUser.setPassword("0000"); // 重置密码
        updateById(dbUser);
    }
}